package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.apis.wemedia.IWemediaClient;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.common.constants.ArticleConstants;
import com.heima.common.constants.BehaviorConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.mess.ArticleVisitStreamMess;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.utils.common.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class HotArticleServiceImpl implements HotArticleService {
    @Autowired
    private ApArticleMapper apArticleMapper;
    @Autowired
    private IWemediaClient wemediaClient;
    @Autowired
    private CacheService cacheService;

    @Override
    public void computeHotArticle() {
        //1 查询最近5天的文章数据
        Date date = DateUtils.addDay(new Date(), -20);
        List<ApArticle> apArticleList = apArticleMapper.findByDays(date);

        //2 计算文章的分值
        List<HotArticleVo> hotArticleVos = computeScore(apArticleList);

        //3 为每个频道缓存10条分支较高的文章
        cacheToRedis(hotArticleVos);
    }

    @Override
    public void updateScore(ArticleVisitStreamMess mess) {
        ApArticle article = apArticleMapper.selectById(mess.getArticleId());

        //频道热点数据
        String json = cacheService.get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + article.getChannelId());
        List<HotArticleVo> vos = JSON.parseArray(json, HotArticleVo.class);
        //替换热点文章
        vos = replaceHotArticle(vos, mess, article);
        //保存替换后的热点文章
        cacheService.set(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + article.getChannelId(),
                JSON.toJSONString(vos));

        //推荐热点数据
        json = cacheService.get(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG);
        vos = JSON.parseArray(json, HotArticleVo.class);
        //替换热点文章
        vos = replaceHotArticle(vos, mess, article);
        //保存替换后的热点文章
        cacheService.set(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG,
                JSON.toJSONString(vos));

    }

    private List<HotArticleVo> replaceHotArticle(List<HotArticleVo> vos, ArticleVisitStreamMess mess,
                                                 ApArticle article) {
        //倍数
        int sc = 3;
        for (HotArticleVo vo : vos) {
            //文章存在，则分数相加
            if (vo.getId().longValue() == mess.getArticleId().longValue()) {
                vo.setScore(vo.getScore() + mess.getView() * 1 * sc);
                vo.setScore(vo.getScore() + mess.getLike() * 3 * sc);
                vo.setScore(vo.getScore() + mess.getComment() * 5 * sc);
                vo.setScore(vo.getScore() + mess.getCollect() * 8 * sc);

                //重新排序并返回
                return vos.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                        .collect(Collectors.toList());
            }
        }

        //文章不存在对比分值最低的文章，进行替换
        HotArticleVo vo = new HotArticleVo();
        BeanUtils.copyProperties(article, vo);
        vo.setScore(mess.getView() * 1 * sc);
        vo.setScore(mess.getLike() * 3 * sc);
        vo.setScore(mess.getComment() * 5 * sc);
        vo.setScore(mess.getCollect() * 8 * sc);

        //热点文章分数低于当前文章，则替换
        if (vos.get(vos.size() - 1).getScore() < vo.getScore()) {
            vos.set(vos.size() - 1, vo);
        }

        //重新排序并返回
        return vos.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                .collect(Collectors.toList());
    }

    //为每个频道缓存10条分值较高的文章
    private void cacheToRedis(List<HotArticleVo> hotArticleVos) {
        //查询频道
        ResponseResult responseResult = wemediaClient.getChannels();

        //判断查询状态码是否不为200
        if (responseResult.getCode().intValue() != 200) {
            return;
        }

        //解析数据，获取频道
        String json = JSON.toJSONString(responseResult.getData());
        List<WmChannel> wmChannelList = JSON.parseArray(json, WmChannel.class);

        //检索每个频道的文章
        for (WmChannel wmChannel : wmChannelList) {
            List<HotArticleVo> channelVos = hotArticleVos.stream()
                    .filter(vo -> vo.getChannelId().intValue() == wmChannel.getId().intValue())
                    .sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                    .limit(10)
                    .collect(Collectors.toList());
            cacheService.set(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + wmChannel.getId(), JSON.toJSONString(channelVos));
        }

        //设置推荐数据
        //获取最高频率的文章并排序
        List<HotArticleVo> vos = hotArticleVos.stream()
                .sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                .limit(10)
                .collect(Collectors.toList());
        cacheService.set(ArticleConstants.HOT_ARTICLE_FIRST_PAGE + ArticleConstants.DEFAULT_TAG, JSON.toJSONString(vos));

    }

    //计算文章分值
    private List<HotArticleVo> computeScore(List<ApArticle> apArticleList) {
        //创建容器
        List<HotArticleVo> vos = new ArrayList<>();
        for (ApArticle article : apArticleList) {
            //复制属性值
            HotArticleVo vo = new HotArticleVo();
            BeanUtils.copyProperties(article, vo);

            //计算分值
            int score = 0;
            //阅读数
            Long readCount = cacheService.hSize(BehaviorConstants.READ_BEHAVIOR
                    + article.getId().toString());
            if (readCount != null)
                score += readCount.intValue();

            //点赞数
            Long likeCount = cacheService.hSize(BehaviorConstants.LIKE_BEHAVIOR
                    + article.getId().toString());
            if (likeCount != null)
                score += likeCount.intValue() * 3;

            //TODO 评论

            //收藏数
            Long collectCount = cacheService.hSize(BehaviorConstants.COLLECTION_BEHAVIOR
                    + article.getId().toString());
            if (collectCount != null)
                score += collectCount.intValue() * 8;

            vo.setScore(score);
            vos.add(vo);
        }

        return vos;
    }
}
